package com.gitee.webdav.kernel;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import com.google.auto.service.AutoService;
import lombok.extern.slf4j.Slf4j;
import org.smartboot.http.common.enums.HeaderNameEnum;
import org.smartboot.http.common.enums.HttpStatus;
import org.smartboot.http.common.utils.Mimetypes;
import org.smartboot.http.server.HttpRequest;
import org.smartboot.http.server.HttpResponse;

import java.io.File;

/**
 * @author hongda.li@hand-china.com
 */
@Slf4j
@AutoService(ResourceReadonlyHandler.class)
public class ResourceHeader extends ResourceReadonlyHandler {

    @Override
    protected MethodEnum method() {
        return MethodEnum.HEAD;
    }

    @Override
    public void handle(HttpRequest request, HttpResponse response) throws Throwable {
        @Remark("请求资源")
        File file = this.path2File(request);

        if (!this.assertFileExists(request, response, file)) {
            return;
        }

        this.writeContentType(response, Mimetypes.getInstance().getMimetype(FileUtil.getName(file)));
        response.addHeader(HeaderNameEnum.ACCEPT_RANGES.getName(), Constants.HttpHeader.RANGE_VALUES);

        Range range = Range.from(request.getHeader(HeaderNameEnum.ACCEPT_RANGES.getName()), file.length());
        if (range == null) {
            response.setHttpStatus(HttpStatus.OK);
            response.setContentLength(file.length());
            this.downloadAll(response, file);
        } else {
            response.setHttpStatus(HttpStatus.PARTIAL_CONTENT);
            response.setContentLength(range.end() - range.start() + 1);
            response.addHeader(HeaderNameEnum.CONTENT_RANGE.getName(), String.format(Constants.HttpHeader.RANGE_FORMAT, range.start(), range.end(), file.length()));
            this.downloadPart(response, file, range);
        }
    }

    protected void downloadAll(HttpResponse response, File file) {
        // none
    }

    protected void downloadPart(HttpResponse response, File file, Range range) {
        // none
    }

    protected record Range(long start, long end, String origin) {

        public static Range from(String rangeHeader, long totalSize) {
            if (CharSequenceUtil.isBlank(rangeHeader)) {
                return null;
            }

            if (!CharSequenceUtil.containsAny(rangeHeader, Constants.HttpHeader.RANGE_VALUES, Constants.HttpHeader.EQUAL, StrPool.DASHED)) {
                return null;
            }

            String[] split = rangeHeader.substring(rangeHeader.lastIndexOf(Constants.HttpHeader.EQUAL) + 1)
                    .trim()
                    .split(StrPool.DASHED);

            // N-""
            if (split.length == 1) {
                return new Range(Long.parseLong(split[0]), totalSize - 1, rangeHeader);
            }

            // ""-M
            if (CharSequenceUtil.isEmpty(split[0])) {
                long end = Long.parseLong(split[1]);
                return new Range(0, end, rangeHeader);
            }

            // N-M
            long start = Long.parseLong(split[0]);
            long end = Long.parseLong(split[1]);
            return new Range(start, Math.min(end, totalSize - 1), rangeHeader);
        }
    }
}
